#ifndef _ISPACKETS_H
#define _ISPACKETS_H
namespace LFS
{
    typedef quint8 byte;
    typedef quint16 word;
    typedef struct _Vec
    {
        quint32 X;
        quint32 Y;
        quint32 Z;
    } Vec;
    typedef struct _Vector
    {
        float X;
        float Y;
        float Z;
    } Vector;

    /////////////////////

    // InSim for Live for Speed : 0.5Z

    // InSim allows communication between up to 8 external programs and LFS.

    // TCP or UDP packets can be sent in both directions, LFS reporting various
    // things about its state, and the external program requesting info and
    // controlling LFS with special packets, text commands or keypresses.

    // NOTE : This text file was written with a TAB size equal to 4 spaces.


    // INSIM VERSION NUMBER (updated for version 0.5X)
    // ====================

    const int INSIM_VERSION = 4;

    // CHANGES in version 0.5Z (compatible so no change to INSIM_VERSION)
    // =======

    // NLP / MCI packets are now output at regular intervals
    // CCI_LAG bit added to the CompCar structure


    // TYPES : (all multi-byte types are PC style - lowest byte first)
    // =====

    // char			1-byte character
    // byte			1-byte unsigned integer
    // word			2-byte unsigned integer
    // short		2-byte signed integer
    // unsigned		4-byte unsigned integer
    // int			4-byte signed integerz
    // float		4-byte float

    // RaceLaps (rl) : (various meanings depending on range)

    // 0       : practice
    // 1-99    : number of laps...   laps  = rl
    // 100-190 : 100 to 1000 laps... laps  = (rl - 100) * 10 + 100
    // 191-238 : 1 to 48 hours...    hours = rl - 190


    // InSim PACKETS
    // =============

    // All InSim packets use a four byte header

    // Size : total packet size - a multiple of 4
    // Type : packet identifier from the ISP_ enum (see below)
    // ReqI : non zero if the packet is a packet request or a reply to a request
    // Data : the first data byte
    typedef enum
    {
        Reply = 0, Request
    } InSimRequestType;

    // INITIALISING InSim
    // ==================

    // To initialise the InSim system, type into LFS : /insim xxxxx
    // where xxxxx is the TCP and UDP port you want LFS to open.

    // OR start LFS with the command line option : LFS /insim=xxxxx
    // This will make LFS listen for packets on that TCP and UDP port.


    // TO START COMMUNICATION
    // ======================

    // TCP : Connect to LFS using a TCP connection, then send this packet :
    // UDP : No connection required, just send this packet to LFS :

    typedef struct IS_ISI // InSim Init - packet to initialise the InSim system
    {
        byte Size; // 44
        byte Type; // ISP_ISI
        byte ReqI; // If non-zero LFS will send an IS_VER packet
        byte Zero; // 0

        word UDPPort; // Port for UDP replies from LFS (0 to 65535)
        word Flags; // Bit flags for options (see below)

        byte Sp0; // 0
        byte Prefix; // Special host message prefix character
        word Interval; // Time in ms between NLP or MCI (0 = none)

        char Admin[16]; // Admin password (if set in LFS)
        char IName[16]; // A short name for your program
    } InSimInitialize;

    // NOTE 1) UDPPort field when you connect using UDP :

    // zero     : LFS sends all packets to the port of the incoming packet
    // non-zero : LFS sends all packets to the specified UDPPort

    // NOTE 2) UDPPort field when you connect using TCP :

    // zero     : LFS sends NLP / MCI packets using your TCP connection
    // non-zero : LFS sends NLP / MCI packets to the specified UDPPort

    // NOTE 3) Flags field (set the relevant bits to turn on the option) :

#define ISF_RES_0		1	// bit 0 : spare
#define ISF_RES_1		2	// bit 1 : spare
#define ISF_LOCAL		4	// bit 2 : guest or single player
#define ISF_MSO_COLS	8	// bit 3 : keep colours in MSO text
#define ISF_NLP			16	// bit 4 : receive NLP packets
#define ISF_MCI			32	// bit 5 : receive MCI packets
    // In most cases you should not set both ISF_NLP and ISF_MCI flags
    // because all IS_NLP information is included in the IS_MCI packet.

    // The ISF_LOCAL flag is important if your program creates buttons.
    // It should be set if your program is not a host control system.
    // If set, then buttons are created in the local button area, so
    // avoiding conflict with the host buttons and allowing the user
    // to switch them with SHIFT+B rather than SHIFT+I.

    // NOTE 4) Prefix field, if set when initialising InSim on a host :

    // Messages typed with this prefix will be sent to your InSim program
    // on the host (in IS_MSO) and not displayed on anyone's screen.


    // ENUMERATIONS FOR PACKET TYPES
    // =============================

    enum // the second byte in all packets is one of these
    {
        ISP_NONE, //  0					: not used
        ISP_ISI, //  1 - instruction		: insim initialise
        ISP_VER, //  2 - info			: version info
        ISP_TINY, //  3 - both ways		: multi purpose
        ISP_SMALL, //  4 - both ways		: multi purpose
        ISP_STA, //  5 - info			: state info
        ISP_SCH, //  6 - instruction		: single character
        ISP_SFP, //  7 - instruction		: state flags pack
        ISP_SCC, //  8 - instruction		: set car camera
        ISP_CPP, //  9 - both ways		: cam pos pack
        ISP_ISM, // 10 - info			: start multiplayer
        ISP_MSO, // 11 - info			: message out
        ISP_III, // 12 - info			: hidden /i message
        ISP_MST, // 13 - instruction		: type message or /command
        ISP_MTC, // 14 - instruction		: message to a connection
        ISP_MOD, // 15 - instruction		: set screen mode
        ISP_VTN, // 16 - info			: vote notification
        ISP_RST, // 17 - info			: race start
        ISP_NCN, // 18 - info			: new connection
        ISP_CNL, // 19 - info			: connection left
        ISP_CPR, // 20 - info			: connection renamed
        ISP_NPL, // 21 - info			: new player (joined race)
        ISP_PLP, // 22 - info			: player pit (keeps slot in race)
        ISP_PLL, // 23 - info			: player leave (spectate - loses slot)
        ISP_LAP, // 24 - info			: lap time
        ISP_SPX, // 25 - info			: split x time
        ISP_PIT, // 26 - info			: pit stop start
        ISP_PSF, // 27 - info			: pit stop finish
        ISP_PLA, // 28 - info			: pit lane enter / leave
        ISP_CCH, // 29 - info			: camera changed
        ISP_PEN, // 30 - info			: penalty given or cleared
        ISP_TOC, // 31 - info			: take over car
        ISP_FLG, // 32 - info			: flag (yellow or blue)
        ISP_PFL, // 33 - info			: player flags (help flags)
        ISP_FIN, // 34 - info			: finished race
        ISP_RES, // 35 - info			: result confirmed
        ISP_REO, // 36 - both ways		: reorder (info or instruction)
        ISP_NLP, // 37 - info			: node and lap packet
        ISP_MCI, // 38 - info			: multi car info
        ISP_MSX, // 39 - instruction		: type message
        ISP_MSL, // 40 - instruction		: message to local computer
        ISP_CRS, // 41 - info			: car reset
        ISP_BFN, // 42 - both ways		: delete buttons / receive button requests
        ISP_AXI, // 43 - info			: autocross layout information
        ISP_AXO, // 44 - info			: hit an autocross object
        ISP_BTN, // 45 - instruction		: show a button on local or remote screen
        ISP_BTC, // 46 - info			: sent when a user clicks a button
        ISP_BTT  // 47 - info			: sent after typing into a button
    };

    enum // the fourth byte of IS_TINY packets is one of these
    {
        TINY_NONE, //  0					: see "maintaining the connection"
        TINY_VER, //  1 - info request	: get version
        TINY_CLOSE, //  2 - instruction		: close insim
        TINY_PING, //  3 - ping request	: external progam requesting a reply
        TINY_REPLY, //  4 - ping reply		: reply to a ping request
        TINY_VTC, //  5 - info			: vote cancelled
        TINY_SCP, //  6 - info request	: send camera pos
        TINY_SST, //  7 - info request	: send state info
        TINY_GTH, //  8 - info request	: get time in hundredths (i.e. SMALL_RTP)
        TINY_MPE, //  9 - info			: multi player end
        TINY_ISM, // 10 - info request	: get multiplayer info (i.e. ISP_ISM)
        TINY_REN, // 11 - info			: race end (return to game setup screen)
        TINY_CLR, // 12 - info			: all players cleared from race
        TINY_NCN, // 13 - info			: get all connections
        TINY_NPL, // 14 - info			: get all players
        TINY_RES, // 15 - info			: get all results
        TINY_NLP, // 16 - info request	: send an IS_NLP
        TINY_MCI, // 17 - info request	: send an IS_MCI
        TINY_REO, // 18 - info request	: send an IS_REO
        TINY_RST, // 19 - info request	: send an IS_RST
        TINY_AXI, // 20 - info request	: send an IS_AXI
        TINY_AXC, // 21 - info			: autocross cleared
    };

    enum // the fourth byte of IS_SMALL packets is one of these
    {
        SMALL_NONE, //  0					: not used
        SMALL_SSP, //  1 - instruction		: start sending positions
        SMALL_SSG, //  2 - instruction		: start sending gauges
        SMALL_VTA, //  3 - report			: vote action
        SMALL_TMS, //  4 - instruction		: time stop
        SMALL_STP, //  5 - instruction		: time step
        SMALL_RTP, //  6 - info			: race time packet (reply to GTH)
        SMALL_NLI,
    //  7 - instruction		: set node lap interval
    };

    // GENERAL PURPOSE PACKETS - IS_TINY (4 bytes) and IS_SMALL (8 bytes)
    // =======================

    // To avoid defining several packet structures that are exactly the same, and to avoid
    // wasting the ISP_ enumeration, IS_TINY is used at various times when no additional data
    // other than SubT is required.  IS_SMALL is used when an additional integer is needed.

    // IS_TINY - used for various requests, replies and reports

    struct IS_TINY // General purpose 4 byte packet
    {
        byte Size; // always 4
        byte Type; // always ISP_TINY
        byte ReqI; // 0 unless it is an info request or a reply to an info request
        byte SubT; // subtype, from TINY_ enumeration (e.g. TINY_RACE_END)
    };

    // IS_SMALL - used for various requests, replies and reports

    struct IS_SMALL // General purpose 8 byte packet
    {
        byte Size; // always 8
        byte Type; // always ISP_SMALL
        byte ReqI; // 0 unless it is an info request or a reply to an info request
        byte SubT; // subtype, from SMALL_ enumeration (e.g. SMALL_SSP)

        unsigned UVal; // value (e.g. for SMALL_SSP this would be the OutSim packet rate)
    };

    // VERSION REQUEST
    // ===============

    // It is advisable to request version information as soon as you have connected, to
    // avoid problems when connecting to a host with a later or earlier version.  You will
    // be sent a version packet on connection if you set ReqI in the IS_ISI packet.

    // This version packet can be sent on request :

    struct IS_VER // VERsion
    {
        byte Size; // 20
        byte Type; // ISP_VERSION
        byte ReqI; // ReqI as received in the request packet
        byte Zero;

        char Version[8]; // LFS version, e.g. 0.3G
        char Product[6]; // Product : DEMO or S1
        word InSimVer; // InSim Version : increased when InSim packets change
    };

    // To request an InSimVersion packet at any time, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_VER		(request an IS_VER)


    // CLOSING InSim
    // =============

    // You can send this IS_TINY to close the InSim connection to your program :

    // ReqI : 0
    // SubT : TINY_CLOSE	(close this connection)

    // Another InSimInit packet is then required to start operating again.

    // You can shut down InSim completely and stop it listening at all by typing /insim=0
    // into LFS (or send a MsgTypePack to do the same thing).


    // MAINTAINING THE CONNECTION - IMPORTANT
    // ==========================

    // If InSim does not receive a packet for 70 seconds, it will close your connection.
    // To open it again you would need to send another InSimInit packet.

    // LFS will send a blank IS_TINY packet like this every 30 seconds :

    // ReqI : 0
    // SubT : TINY_NONE		(keep alive packet)

    // You should reply with a blank IS_TINY packet :

    // ReqI : 0
    // SubT : TINY_NONE		(has no effect other than resetting the timeout)

    // NOTE : If you want to request a reply from LFS to check the connection
    // at any time, you can send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_PING		(request a TINY_REPLY)

    // LFS will reply with this IS_TINY :

    // ReqI : non-zero		(as received in the request packet)
    // SubT : TINY_REPLY	(reply to ping)


    // STATE REPORTING AND REQUESTS
    // ============================

    // LFS will send a StatePack any time the info in the StatePack changes.

    struct IS_STA // STAte
    {
        byte Size; // 28
        byte Type; // ISP_STA
        byte ReqI; // ReqI if replying to a request packet
        byte Zero;

        float ReplaySpeed; // 4-byte float - 1.0 is normal speed

        word Flags; // ISS state flags (see below)
        byte InGameCam; // Which type of camera is selected (see below)
        byte ViewPLID; // Unique ID of viewed player (0 = none)

        byte NumP; // Number of players in race
        byte NumConns; // Number of connections including host
        byte NumFinished; // Number finished or qualified
        byte RaceInProg; // 0 - no race / 1 - race / 2 - qualifying

        byte QualMins;
        byte RaceLaps; // see "RaceLaps" near the top of this document
        byte Spare2;
        byte Spare3;

        char Track[6]; // short name for track e.g. FE2R
        byte Weather; // 0,1,2...
        byte Wind; // 0=off 1=weak 2=strong
    };

    // InGameCam is the in game selected camera mode (which is
    // still selected even if LFS is actually in SHIFT+U mode).
    // For InGameCam's values, see "View identifiers" below.

    // ISS state flags

#define ISS_GAME			1		// in game (or MPR)
#define ISS_REPLAY			2		// in SPR
#define ISS_PAUSED			4		// paused
#define ISS_SHIFTU			8		// SHIFT+U mode
#define ISS_SHIFTU_HIGH		16		// HIGH view
#define ISS_SHIFTU_FOLLOW	32		// following car
#define ISS_SHIFTU_NO_OPT	64		// SHIFT+U buttons hidden
#define ISS_SHOW_2D			128		// showing 2d display
#define ISS_FRONT_END		256		// entry screen
#define ISS_MULTI			512		// multiplayer mode
#define ISS_MPSPEEDUP		1024	// multiplayer speedup option
#define ISS_WINDOWED		2048	// LFS is running in a window
#define ISS_SOUND_MUTE		4096	// sound is switched off
#define ISS_VIEW_OVERRIDE	8192	// override user view
#define ISS_VISIBLE			16384	// InSim buttons visible
    // To request a StatePack at any time, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_SST		(Send STate)

    // Setting states

    // These states can be set by a special packet :

    // ISS_SHIFTU_FOLLOW	- following car
    // ISS_SHIFTU_NO_OPT	- SHIFT+U buttons hidden
    // ISS_SHOW_2D			- showing 2d display
    // ISS_MPSPEEDUP		- multiplayer speedup option
    // ISS_SOUND_MUTE		- sound is switched off

    struct IS_SFP // State Flags Pack
    {
        byte Size; // 8
        byte Type; // ISP_SFP
        byte ReqI; // 0
        byte Zero;

        word Flag; // the state to set
        byte OffOn; // 0 = off / 1 = on
        byte Sp3; // spare
    };

    // Other states must be set by using keypresses or messages (see below)


    // SCREEN MODE
    // ===========

    // You can send this packet to LFS to set the screen mode :

    struct IS_MOD // MODe : send to LFS to change screen mode
    {
        byte Size; // 20
        byte Type; // ISP_MOD
        byte ReqI; // 0
        byte Zero;

        int Bits16; // set to choose 16-bit
        int RR; // refresh rate - zero for default
        int Width; // 0 means go to window
        int Height; // 0 means go to window
    };

    // The refresh rate actually selected by LFS will be the highest available rate
    // that is less than or equal to the specified refresh rate.  Refresh rate can
    // be specified as zero in which case the default refresh rate will be used.

    // If Width and Height are both zero, LFS will switch to windowed mode.


    // TEXT MESSAGES AND KEY PRESSES
    // ==============================

    // You can send 64-byte text messages to LFS as if the user had typed them in.
    // Messages that appear on LFS screen (up to 128 bytes) are reported to the
    // external program.  You can also send simulated keypresses to LFS.

    // MESSAGES OUT (FROM LFS)
    // ------------

    struct IS_MSO // MSg Out - system messages and user messages
    {
        byte Size; // 136
        byte Type; // ISP_MSO
        byte ReqI; // 0
        byte Zero;

        byte UCID; // connection's unique id (0 = host)
        byte PLID; // player's unique id (if zero, use UCID)
        byte UserType; // set if typed by a user (see User Values below)
        byte TextStart; // first character of the actual text (after player name)

        char Msg[128];
    };

    // User Values (for UserType byte)

    enum
    {
        MSO_SYSTEM, // 0 - system message
        MSO_USER, // 1 - normal visible user message
        MSO_PREFIX, // 2 - hidden message starting with special prefix (see ISI)
        MSO_O, // 3 - hidden message typed on local pc with /o command
        MSO_NUM
    };

    // NOTE : Typing "/o MESSAGE" into LFS will send an IS_MSO with UserType = MSO_O

    struct IS_III // InsIm Info - /i message from user to host's InSim
    {
        byte Size; // 72
        byte Type; // ISP_III
        byte ReqI; // 0
        byte Zero;

        byte UCID; // connection's unique id (0 = host)
        byte PLID; // player's unique id (if zero, use UCID)
        byte Sp2;
        byte Sp3;

        char Msg[64];
    };

    // MESSAGES IN (TO LFS)
    // -----------

    struct IS_MST // MSg Type - send to LFS to type message or command
    {
        byte Size; // 68
        byte Type; // ISP_MST
        byte ReqI; // 0
        byte Zero;

        char Msg[64]; // last byte must be zero
    };

    struct IS_MSX // MSg eXtended - like MST but longer (not for commands)
    {
        byte Size; // 100
        byte Type; // ISP_MSX
        byte ReqI; // 0
        byte Zero;

        char Msg[96]; // last byte must be zero
    };

    struct IS_MSL // MSg Local - message to appear on local computer only
    {
        byte Size; // 132
        byte Type; // ISP_MSL
        byte ReqI; // 0
        byte Sound; // sound effect (see Message Sounds below)

        char Msg[128]; // last byte must be zero
    };

    struct IS_MTC // Msg To Connection - hosts only - send to a connection or a player
    {
        byte Size; // 72
        byte Type; // ISP_MTC
        byte ReqI; // 0
        byte Zero;

        byte UCID; // connection's unique id (0 = host)
        byte PLID; // player's unique id (if zero, use UCID)
        byte Sp2;
        byte Sp3;

        char Msg[64]; // last byte must be zero
    };

    struct IS_SCH // Single CHaracter - send to simulate single character
    {
        byte Size; // 8
        byte Type; // ISP_SCH
        byte ReqI; // 0
        byte Zero;

        byte CharB; // key to press
        byte Flags; // bit 0 : SHIFT / bit 1 : CTRL
        byte Spare2;
        byte Spare3;
    };

    // Message Sounds (for Sound byte)

    enum
    {
        SND_SILENT, SND_MESSAGE, SND_SYSMESSAGE, SND_INVALIDKEY, SND_ERROR, SND_NUM
    };

    // MULTIPLAYER NOTIFICATION
    // ========================

    // LFS will send this packet when a host is started or joined :

    struct IS_ISM // InSim Multi
    {
        byte Size; // 40
        byte Type; // ISP_ISM
        byte ReqI; // usually 0 / or if a reply : ReqI as received in the TINY_ISM
        byte Zero;

        byte Host; // 0 = guest / 1 = host
        byte Sp1;
        byte Sp2;
        byte Sp3;

        char HName[32]; // the name of the host joined or started
    };

    // On ending or leaving a host, LFS will send this IS_TINY :

    // ReqI : 0
    // SubT : TINY_MPE		(MultiPlayerEnd)

    // To request an IS_ISM packet at any time, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_ISM		(request an IS_ISM)

    // NOTE : If LFS is not in multiplayer mode, the host name in the ISM will be empty.


    // VOTE NOTIFY AND CANCEL
    // ======================

    // LFS notifies the external program of any votes to restart or qualify

    // The Vote Actions are defined as :

    enum
    {
        VOTE_NONE, // 0 - no vote
        VOTE_END, // 1 - end race
        VOTE_RESTART, // 2 - restart
        VOTE_QUALIFY, // 3 - qualify
        VOTE_NUM
    };

    struct IS_VTN // VoTe Notify
    {
        byte Size; // 8
        byte Type; // ISP_VTN
        byte ReqI; // 0
        byte Zero;

        byte UCID; // connection's unique id
        byte Action; // VOTE_X (Vote Action as defined above)
        byte Spare2;
        byte Spare3;
    };

    // When a vote is cancelled, LFS sends this IS_TINY

    // ReqI : 0
    // SubT : TINY_VTC		(VoTe Cancelled)

    // When a vote is completed, LFS sends this IS_SMALL

    // ReqI : 0
    // SubT : SMALL_VTA  	(VoTe Action)
    // UVal : action 		(VOTE_X - Vote Action as defined above)

    // You can instruct LFS host to cancel a vote using an IS_TINY

    // ReqI : 0
    // SubT : TINY_VTC		(VoTe Cancel)


    // RACE TRACKING
    // =============

    // In LFS there is a list of connections AND a list of players in the race
    // Some packets are related to connections, some players, some both

    // If you are making a multiplayer InSim program, you must maintain two lists
    // You should use the unique identifier UCID to identify a connection

    // Each player has a unique identifier PLID from the moment he joins the race, until he
    // leaves.  It's not possible for PLID and UCID to be the same thing, for two reasons :

    // 1) there may be more than one player per connection if AI drivers are used
    // 2) a player can swap between connections, in the case of a driver swap (IS_TOC)

    // When all players are cleared from race (e.g. /clear) LFS sends this IS_TINY

    // ReqI : 0
    // SubT : TINY_CLR		(CLear Race)

    // When a race ends (return to game setup screen) LFS sends this IS_TINY

    // ReqI : 0
    // SubT : TINY_REN  	(Race ENd)

    // You can instruct LFS host to cancel a vote using an IS_TINY

    // ReqI : 0
    // SubT : TINY_VTC		(VoTe Cancel)


    struct IS_RST // Race STart
    {
        byte Size; // 28
        byte Type; // ISP_RST
        byte ReqI; // 0 unless this is a reply to an TINY_RST request
        byte Zero;

        byte RaceLaps; // 0 if qualifying
        byte QualMins; // 0 if race
        byte NumP; // number of players in race
        byte Spare;

        char Track[6]; // short track name
        byte Weather;
        byte Wind;

        word Flags; // race flags (must pit, can reset, etc - see below)
        word NumNodes; // total number of nodes in the path
        word Finish; // node index - finish line
        word Split1; // node index - split 1
        word Split2; // node index - split 2
        word Split3; // node index - split 3
    };

    // To request an IS_RST packet at any time, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_RST		(request an IS_RST)

    struct IS_NCN // New ConN
    {
        byte Size; // 56
        byte Type; // ISP_NCN
        byte ReqI; // 0 unless this is a reply to a TINY_NCN request
        byte UCID; // new connection's unique id (0 = host)

        char UName[24]; // username
        char PName[24]; // nickname

        byte Admin; // 1 if admin
        byte Total; // number of connections including host
        byte Flags; // bit 2 : remote
        byte Sp3;
    };

    struct IS_CNL // ConN Leave
    {
        byte Size; // 8
        byte Type; // ISP_CNL
        byte ReqI; // 0
        byte UCID; // unique id of the connection which left

        byte Reason; // leave reason (see below)
        byte Total; // number of connections including host
        byte Sp2;
        byte Sp3;
    };

    struct IS_CPR // Conn Player Rename
    {
        byte Size; // 36
        byte Type; // ISP_CPR
        byte ReqI; // 0
        byte UCID; // unique id of the connection

        char PName[24]; // new name
        char Plate[8]; // number plate - NO ZERO AT END!
    };

    struct IS_NPL // New PLayer joining race (if PLID already exists, then leaving pits)
    {
        byte Size; // 76
        byte Type; // ISP_NPL
        byte ReqI; // 0 unless this is a reply to an TINY_NPL request
        byte PLID; // player's newly assigned unique id

        byte UCID; // connection's unique id
        byte PType; // bit 0 : female / bit 1 : AI / bit 2 : remote
        word Flags; // player flags

        char PName[24]; // nickname
        char Plate[8]; // number plate - NO ZERO AT END!

        char CName[4]; // car name
        char SName[16]; // skin name - MAX_CAR_TEX_NAME
        byte Tyres[4]; // compounds

        byte H_Mass; // added mass (kg)
        byte H_TRes; // intake restriction
        byte Model; // driver model
        byte Pass; // passengers byte

        int Spare;

        byte Sp0;
        byte NumP; // number in race (same when leaving pits, 1 more if new)
        byte Sp2;
        byte Sp3;
    };

    // NOTE : PType bit 0 (female) is not reported on dedicated host as humans are not loaded
    // You can use the driver model byte instead if required (and to force the use of helmets)

    struct IS_PLP // PLayer Pits (go to settings - stays in player list)
    {
        byte Size; // 4
        byte Type; // ISP_PLP
        byte ReqI; // 0
        byte PLID; // player's unique id
    };

    struct IS_PLL // PLayer Leave race (spectate - removed from player list)
    {
        byte Size; // 4
        byte Type; // ISP_PLL
        byte ReqI; // 0
        byte PLID; // player's unique id
    };

    struct IS_CRS // Car ReSet
    {
        byte Size; // 4
        byte Type; // ISP_CRS
        byte ReqI; // 0
        byte PLID; // player's unique id
    };

    struct IS_LAP // LAP time
    {
        byte Size; // 20
        byte Type; // ISP_LAP
        byte ReqI; // 0
        byte PLID; // player's unique id

        unsigned LTime; // lap time (ms)
        unsigned ETime; // total time (ms)

        word LapsDone; // laps completed
        word Flags; // player flags

        byte Sp0;
        byte Penalty; // current penalty value (see below)
        byte NumStops; // number of pit stops
        byte Sp3;
    };

    struct IS_SPX // SPlit X time
    {
        byte Size; // 16
        byte Type; // ISP_SPX
        byte ReqI; // 0
        byte PLID; // player's unique id

        unsigned STime; // split time (ms)
        unsigned ETime; // total time (ms)

        byte Split; // split number 1, 2, 3
        byte Penalty; // current penalty value (see below)
        byte NumStops; // number of pit stops
        byte Sp3;
    };

    struct IS_PIT // PIT stop (stop at pit garage)
    {
        byte Size; // 24
        byte Type; // ISP_PIT
        byte ReqI; // 0
        byte PLID; // player's unique id

        word LapsDone; // laps completed
        word Flags; // player flags

        byte Sp0;
        byte Penalty; // current penalty value (see below)
        byte NumStops; // number of pit stops
        byte Sp3;

        byte Tyres[4]; // tyres changed

        unsigned Work; // pit work
        unsigned Spare;
    };

    struct IS_PSF // Pit Stop Finished
    {
        byte Size; // 12
        byte Type; // ISP_PSF
        byte ReqI; // 0
        byte PLID; // player's unique id

        unsigned STime; // stop time (ms)
        unsigned Spare;
    };

    struct IS_PLA // Pit LAne
    {
        byte Size; // 8
        byte Type; // ISP_PLA
        byte ReqI; // 0
        byte PLID; // player's unique id

        byte Fact; // pit lane fact (see below)
        byte Sp1;
        byte Sp2;
        byte Sp3;
    };

    // IS_CCH : Camera CHange

    // To track cameras you need to consider 3 points

    // 1) The default camera : VIEW_DRIVER
    // 2) Player flags : CUSTOM_VIEW means VIEW_CUSTOM at start or pit exit
    // 3) IS_CCH : sent when an existing driver changes camera

    struct IS_CCH // Camera CHange
    {
        byte Size; // 8
        byte Type; // ISP_CCH
        byte ReqI; // 0
        byte PLID; // player's unique id

        byte Camera; // view identifier (see below)
        byte Sp1;
        byte Sp2;
        byte Sp3;
    };

    struct IS_PEN // PENalty (given or cleared)
    {
        byte Size; // 8
        byte Type; // ISP_PEN
        byte ReqI; // 0
        byte PLID; // player's unique id

        byte OldPen; // old penalty value (see below)
        byte NewPen; // new penalty value (see below)
        byte Reason; // penalty reason (see below)
        byte Sp3;
    };

    struct IS_TOC // Take Over Car
    {
        byte Size; // 8
        byte Type; // ISP_TOC
        byte ReqI; // 0
        byte PLID; // player's unique id

        byte OldUCID; // old connection's unique id
        byte NewUCID; // new connection's unique id
        byte Sp2;
        byte Sp3;
    };

    struct IS_FLG // FLaG (yellow or blue flag changed)
    {
        byte Size; // 8
        byte Type; // ISP_FLG
        byte ReqI; // 0
        byte PLID; // player's unique id

        byte OffOn; // 0 = off / 1 = on
        byte Flag; // 1 = given blue / 2 = causing yellow
        byte CarBehind; // unique id of obstructed player
        byte Sp3;
    };

    struct IS_PFL // Player FLags (help flags changed)
    {
        byte Size; // 8
        byte Type; // ISP_PFL
        byte ReqI; // 0
        byte PLID; // player's unique id

        word Flags; // player flags (see below)
        word Spare;
    };

    struct IS_FIN // FINished race notification (not a final result - use IS_RES)
    {
        byte Size; // 20
        byte Type; // ISP_FIN
        byte ReqI; // 0
        byte PLID; // player's unique id (0 = player left before result was sent)

        unsigned TTime; // race time (ms)
        unsigned BTime; // best lap (ms)

        byte SpA;
        byte NumStops; // number of pit stops
        byte Confirm; // confirmation flags : disqualified etc - see below
        byte SpB;

        word LapsDone; // laps completed
        word Flags; // player flags : help settings etc - see below
    };

    struct IS_RES // RESult (qualify or confirmed finish)
    {
        byte Size; // 84
        byte Type; // ISP_RES
        byte ReqI; // 0 unless this is a reply to a TINY_RES request
        byte PLID; // player's unique id (0 = player left before result was sent)

        char UName[24]; // username
        char PName[24]; // nickname
        char Plate[8]; // number plate - NO ZERO AT END!
        char CName[4]; // skin prefix

        unsigned TTime; // race time (ms)
        unsigned BTime; // best lap (ms)

        byte SpA;
        byte NumStops; // number of pit stops
        byte Confirm; // confirmation flags : disqualified etc - see below
        byte SpB;

        word LapsDone; // laps completed
        word Flags; // player flags : help settings etc - see below

        byte ResultNum; // finish or qualify pos (0 = win / 255 = not added to table)
        byte NumRes; // total number of results (qualify doesn't always add a new one)
        word PSeconds; // penalty time in seconds (already included in race time)
    };

    // IS_REO : REOrder - this packet can be sent in either direction

    // LFS sends one at the start of every race or qualifying session, listing the start order

    // You can send one to LFS before a race start, to specify the starting order.
    // It may be a good idea to avoid conflict by using /start=fixed (LFS setting).
    // Alternatively, you can leave the LFS setting, but make sure you send your IS_REO
    // AFTER you receive the IS_VTA.  LFS does its default grid reordering at the same time
    // as it sends the IS_VTA (VoTe Action) and you can override this by sending an IS_REO.

    struct IS_REO // REOrder (when race restarts after qualifying)
    {
        byte Size; // 36
        byte Type; // ISP_REO
        byte ReqI; // 0 unless this is a reply to an TINY_REO request
        byte NumP; // number of players in race

        byte PLID[32]; // all PLIDs in new order
    };

    // To request an IS_REO packet at any time, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_REO		(request an IS_REO)

    // Pit Lane Facts

    enum
    {
        PITLANE_EXIT, // 0 - left pit lane
        PITLANE_ENTER, // 1 - entered pit lane
        PITLANE_NO_PURPOSE, // 2 - entered for no purpose
        PITLANE_DT, // 3 - entered for drive-through
        PITLANE_SG, // 4 - entered for stop-go
        PITLANE_NUM
    };

    // Pit Work Flags

    enum
    {
        PSE_NOTHING, // bit 0 (1)
        PSE_STOP, // bit 1 (2)
        PSE_FR_DAM, // bit 2 (4)
        PSE_FR_WHL, // etc...
        PSE_LE_FR_DAM,
        PSE_LE_FR_WHL,
        PSE_RI_FR_DAM,
        PSE_RI_FR_WHL,
        PSE_RE_DAM,
        PSE_RE_WHL,
        PSE_LE_RE_DAM,
        PSE_LE_RE_WHL,
        PSE_RI_RE_DAM,
        PSE_RI_RE_WHL,
        PSE_BODY_MINOR,
        PSE_BODY_MAJOR,
        PSE_SETUP,
        PSE_REFUEL,
        PSE_NUM
    };

    // View identifiers

    enum
    {
        VIEW_FOLLOW, // 0 - arcade
        VIEW_HELI, // 1 - helicopter
        VIEW_CAM, // 2 - tv camera
        VIEW_DRIVER, // 3 - cockpit
        VIEW_CUSTOM, // 4 - custom
        VIEW_MAX
    };

    const int VIEW_ANOTHER = 255; // viewing another car

    // Leave reasons

    enum
    {
        LEAVR_DISCO, // 0 - disconnect
        LEAVR_TIMEOUT, // 1 - timed out
        LEAVR_LOSTCONN, // 2 - lost connection
        LEAVR_KICKED, // 3 - kicked
        LEAVR_BANNED, // 4 - banned
        LEAVR_SECURITY, // 5 - OOS or cheat protection
        LEAVR_NUM
    };

    // Penalty values (VALID means the penalty can now be cleared)

    enum
    {
        PENALTY_NONE, // 0
        PENALTY_DT, // 1
        PENALTY_DT_VALID, // 2
        PENALTY_SG, // 3
        PENALTY_SG_VALID, // 4
        PENALTY_30, // 5
        PENALTY_45, // 6
        PENALTY_NUM
    };

    // Penalty reasons

    enum
    {
        PENR_UNKNOWN, // 0 - unknown or cleared penalty
        PENR_ADMIN, // 1 - penalty given by admin
        PENR_WRONG_WAY, // 2 - wrong way driving
        PENR_FALSE_START, // 3 - starting before green light
        PENR_SPEEDING, // 4 - speeding in pit lane
        PENR_STOP_SHORT, // 5 - stop-go pit stop too short
        PENR_STOP_LATE, // 6 - compulsory stop is too late
        PENR_NUM
    };

    // Player flags

#define PIF_SWAPSIDE		1
#define PIF_RESERVED_2		2
#define PIF_RESERVED_4		4
#define PIF_AUTOGEARS		8
#define PIF_SHIFTER			16
#define PIF_RESERVED_32		32
#define PIF_HELP_B			64
#define PIF_AXIS_CLUTCH		128
#define PIF_INPITS			256
#define PIF_AUTOCLUTCH		512
#define PIF_MOUSE			1024
#define PIF_KB_NO_HELP		2048
#define PIF_KB_STABILISED	4096
#define PIF_CUSTOM_VIEW		8192

    // Tyre compounds (4 byte order : rear L, rear R, front L, front R)

    enum
    {
        TYRE_R1, // 0
        TYRE_R2, // 1
        TYRE_R3, // 2
        TYRE_R4, // 3
        TYRE_ROAD_SUPER, // 4
        TYRE_ROAD_NORMAL, // 5
        TYRE_HYBRID, // 6
        TYRE_KNOBBLY, // 7
        TYRE_NUM
    };

    const int NOT_CHANGED = 255;

    // Confirmation flags

#define CONF_MENTIONED		1
#define CONF_CONFIRMED		2
#define CONF_PENALTY_DT		4
#define CONF_PENALTY_SG		8
#define CONF_PENALTY_30		16
#define CONF_PENALTY_45		32
#define CONF_DID_NOT_PIT	64

#define CONF_DISQ	(CONF_PENALTY_DT | CONF_PENALTY_SG | CONF_DID_NOT_PIT)
#define CONF_TIME	(CONF_PENALTY_30 | CONF_PENALTY_45)

    // Race flags

    // HOSTF_CAN_VOTE		1
    // HOSTF_CAN_SELECT		2
    // HOSTF_MID_RACE		32
    // HOSTF_MUST_PIT		64
    // HOSTF_CAN_RESET		128
    // HOSTF_FCV			256
    // HOSTF_CRUISE			512

    // Passengers byte

    // bit 0 female
    // bit 1 front
    // bit 2 female
    // bit 3 rear left
    // bit 4 female
    // bit 5 rear middle
    // bit 6 female
    // bit 7 rear right


    // TRACKING PACKET REQUESTS
    // ========================

    // To request players, connections, results or a single NLP or MCI, send an IS_TINY

    // In each case, ReqI must be non-zero, and will be returned in the reply packet

    // SubT : TINT_NCN - request all connections
    // SubT : TINY_NPL - request all players
    // SubT : TINY_RES - request all results
    // SubT : TINY_NLP - request a single IS_NLP
    // SubT : TINY_MCI - request a set of IS_MCI


    // AUTOCROSS
    // =========

    // When all objects are cleared from a layout, LFS sends this IS_TINY :

    // ReqI : 0
    // SubT : TINY_AXC		(AutoX Cleared)

    // You can request information about the current layout with this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_AXI		(AutoX Info)

    // The information will be sent back in this packet (also sent when a layout is loaded) :

    struct IS_AXI // AutoX Info
    {
        byte Size; // 40
        byte Type; // ISP_AXI
        byte ReqI; // 0 unless this is a reply to an TINY_AXI request
        byte Zero;

        byte AXStart; // autocross start position
        byte NumCP; // number of checkpoints
        word NumO; // number of objects

        char LName[32]; // the name of the layout last loaded (if loaded locally)
    };

    // On false start or wrong route / restricted area, an IS_PEN packet is sent :

    // False start : OldPen = 0 / NewPen = PENALTY_30 / Reason = PENR_FALSE_START
    // Wrong route : OldPen = 0 / NewPen = PENALTY_45 / Reason = PENR_WRONG_WAY

    // If an autocross object is hit (2 second time penalty) this packet is sent :

    struct IS_AXO // AutoX Object
    {
        byte Size; // 4
        byte Type; // ISP_AXO
        byte ReqI; // 0
        byte PLID; // player's unique id
    };

    // CAR TRACKING - car position info sent at constant intervals
    // ============

    // IS_NLP - compact, all cars in 1 variable sized packet
    // IS_MCI - detailed, max 8 cars per variable sized packet

    // To receive IS_NLP or IS_MCI packets at a specified interval :

    // 1) Set the Interval field in the IS_ISI (InSimInit) packet (50, 60, 70... 8000 ms)
    // 2) Set one of the flags ISF_NLP or ISF_MCI in the IS_ISI packet

    // If ISF_NLP flag is set, one IS_NLP packet is sent...

    struct NodeLap // Car info in 6 bytes - there is an array of these in the NLP (below)
    {
        word Node; // current path node
        word Lap; // current lap
        byte PLID; // player's unique id
        byte Position; // current race position : 0 = unknown, 1 = leader, etc...
    };

    struct IS_NLP // Node and Lap Packet - variable size
    {
        byte Size; // 4 + NumP * 6 (PLUS 2 if needed to make it a multiple of 4)
        byte Type; // ISP_NLP
        byte ReqI; // 0 unless this is a reply to an TINY_NLP request
        byte NumP; // number of players in race

        NodeLap Info[32]; // node and lap of each player, 1 to 32 of these (NumP)
    };

    // If ISF_MCI flag is set, a set of IS_MCI packets is sent...

    struct CompCar // Car info in 28 bytes - there is an array of these in the MCI (below)
    {
        word Node; // current path node
        word Lap; // current lap
        byte PLID; // player's unique id
        byte Position; // current race position : 0 = unknown, 1 = leader, etc...
        byte Info; // flags and other info - see below
        byte Sp3;
        int X; // X map (65536 = 1 metre)
        int Y; // Y map (65536 = 1 metre)
        int Z; // Z alt (65536 = 1 metre)
        word Speed; // speed (32768 = 100 m/s)
        word Direction; // direction of car's motion : 0 = world y direction, 32768 = 180 deg
        word Heading; // direction of forward axis : 0 = world y direction, 32768 = 180 deg
        short AngVel; // signed, rate of change of heading : (16384 = 360 deg/s)
    };

    // NOTE 1) Info byte - the bits in this byte have the following meanings :

#define CCI_BLUE		1		// this car is in the way of a driver who is a lap ahead
#define CCI_YELLOW		2		// this car is slow or stopped and in a dangerous place
#define CCI_LAG			32		// this car is lagging (missing or delayed position packets)
#define CCI_FIRST		64		// this is the first compcar in this set of MCI packets
#define CCI_LAST		128		// this is the last compcar in this set of MCI packets
    // NOTE 2) Heading : 0 = world y axis direction, 32768 = 180 degrees, anticlockwise from above
    // NOTE 3) AngVel  : 0 = no change in heading,    8192 = 180 degrees per second anticlockwise

    struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
    {
        byte Size; // 4 + NumP * 28
        byte Type; // ISP_MCI
        byte ReqI; // 0 unless this is a reply to an TINY_MCI request
        byte NumC; // number of valid CompCar structs in this packet

        CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
    };

    // You can change the rate of NLP or MCI after initialisation by sending this IS_SMALL :

    // ReqI : 0
    // SubT : SMALL_NLI		(Node Lap Interval)
    // UVal : interval      (0 means stop, otherwise time interval : 50, 60, 70... 8000 ms)


    // CAR POSITION PACKETS (Initialising OutSim from InSim - See "OutSim" below)
    // ====================

    // To request Car Positions from the currently viewed car, send this IS_SMALL :

    // ReqI : 0
    // SubT : SMALL_SSP		(Start Sending Positions)
    // UVal : interval		(time between updates - zero means stop sending)

    // If OutSim has not been setup in cfg.txt, the SSP packet makes LFS send UDP packets
    // if in game, using the OutSim system as documented near the end of this text file.

    // You do not need to set any OutSim values in LFS cfg.txt - OutSim is fully
    // initialised by the SSP packet.

    // The OutSim packets will be sent to the UDP port specified in the InSimInit packet.

    // NOTE : OutSim packets are not InSim packets and don't have a 4-byte header.


    // DASHBOARD PACKETS (Initialising OutGauge from InSim - See "OutGauge" below)
    // =================

    // To request Dashboard Packets from the currently viewed car, send this IS_SMALL :

    // ReqI : 0
    // SubT : SMALL_SSG		(Start Sending Gauges)
    // UVal : interval		(time between updates - zero means stop sending)

    // If OutGauge has not been setup in cfg.txt, the SSG packet makes LFS send UDP packets
    // if in game, using the OutGauge system as documented near the end of this text file.

    // You do not need to set any OutGauge values in LFS cfg.txt - OutGauge is fully
    // initialised by the SSG packet.

    // The OutGauge packets will be sent to the UDP port specified in the InSimInit packet.

    // NOTE : OutGauge packets are not InSim packets and don't have a 4-byte header.


    // CAMERA CONTROL
    // ==============

    // IN GAME camera control
    // ----------------------

    // You can set the viewed car and selected camera directly with a special packet
    // These are the states normally set in game by using the TAB and V keys

    struct IS_SCC // Set Car Camera - Simplified camera packet (not SHIFT+U mode)
    {
        byte Size; // 8
        byte Type; // ISP_SCC
        byte ReqI; // 0
        byte Zero;

        byte ViewPLID; // UniqueID of player to view
        byte InGameCam; // InGameCam (as reported in StatePack)
        byte Sp2;
        byte Sp3;
    };

    // NOTE : Set InGameCam or ViewPLID to 255 to leave that option unchanged.

    // DIRECT camera control
    // ---------------------

    // A Camera Position Packet can be used for LFS to report a camera position and state.
    // An InSim program can also send one to set LFS camera position in game or SHIFT+U mode.

    // Type : "Vec" : 3 ints (X, Y, Z) - 65536 means 1 metre

    struct IS_CPP // Cam Pos Pack - Full camera packet (in car OR SHIFT+U mode)
    {
        byte Size; // 32
        byte Type; // ISP_CPP
        byte ReqI; // instruction : 0 / or reply : ReqI as received in the TINY_SCP
        byte Zero;

        Vec Pos; // Position vector

        word H; // heading - 0 points along Y axis
        word P; // pitch   - 0 means looking at horizon
        word R; // roll    - 0 means no roll

        byte ViewPLID; // Unique ID of viewed player (0 = none)
        byte InGameCam; // InGameCam (as reported in StatePack)

        float FOV; // 4-byte float : FOV in degrees

        word Time; // Time to get there (0 means instant + reset)
        word Flags; // ISS state flags (see below)
    };

    // The ISS state flags that can be set are :

    // ISS_SHIFTU			- in SHIFT+U mode
    // ISS_SHIFTU_HIGH		- HIGH view
    // ISS_SHIFTU_FOLLOW	- following car
    // ISS_VIEW_OVERRIDE	- override user view

    // On receiving this packet, LFS will set up the camera to match the values in the packet,
    // including switching into or out of SHIFT+U mode depending on the ISS_SHIFTU flag.

    // If ISS_SHIFTU is not set, then ViewPLID and InGameCam will be used.

    // If ISS_VIEW_OVERRIDE is set, the in-car view Heading Pitch and Roll will be taken
    // from the values in this packet.  Otherwise normal in game control will be used.

    // Position vector (Vec Pos) - in SHIFT+U mode, Pos can be either relative or absolute.

    // If ISS_SHIFTU_FOLLOW is set, it's a following camera, so the position is relative to
    // the selected car.  Otherwise, the position is absolute, as used in normal SHIFT+U mode.

    // NOTE : Set InGameCam or ViewPLID to 255 to leave that option unchanged.

    // SMOOTH CAMERA POSITIONING
    // --------------------------

    // The "Time" value in the packet is used for camera smoothing.  A zero Time means instant
    // positioning.  Any other value (milliseconds) will cause the camera to move smoothly to
    // the requested position in that time.  This is most useful in SHIFT+U camera modes or
    // for smooth changes of internal view when using the ISS_VIEW_OVERRIDE flag.

    // NOTE : You can use frequently updated camera positions with a longer Time value than
    // the update frequency.  For example, sending a camera position every 100 ms, with a
    // Time value of 1000 ms.  LFS will make a smooth motion from the rough inputs.

    // If the requested camera mode is different from the one LFS is already in, it cannot
    // move smoothly to the new position, so in this case the "Time" value is ignored.

    // GETTING A CAMERA PACKET
    // -----------------------

    // To GET a CamPosPack from LFS, send this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_SCP		(Send Cam Pos)

    // LFS will reply with a CamPosPack as described above.  You can store this packet
    // and later send back exactly the same packet to LFS and it will try to replicate
    // that camera position.


    // TIME CONTROL
    // ============

    // You can Stop or Start Time in LFS and while it is stopped you can make LFS move
    // in time steps in multiples of 100th of a second.  Warning : unlike pausing, this
    // is a "trick" to LFS and the program is unaware of time passing, so you must not
    // leave it stopped because LFS is unusable in that state.  You must never use this
    // packet in multiplayer mode.

    // Request the current time at any point with this IS_TINY :

    // ReqI : non-zero		(returned in the reply)
    // SubT : TINY_GTH		(Get Time in Hundredths)

    // The time will be sent back in this IS_SMALL :

    // ReqI : non-zero		(as received in the request packet)
    // SubT : SMALL_RTP		(Race Time Packet)
    // UVal	: Time			(hundredths of a second since start of race or replay)

    // Stop and Start with this IS_SMALL :

    // ReqI : 0
    // SubT : SMALL_TMS		(TiMe Stop)
    // UVal	: stop			(1 - stop / 0 - carry on)

    // When STOPPED, make time step updates with this IS_SMALL :

    // ReqI : 0
    // SubT : SMALL_STP		(STeP)
    // UVal : number		(number of hundredths of a second to update)


    // BUTTONS
    // =======

    // You can make up to 240 buttons appear on the host or guests (ID = 0 to 239).
    // You should set the ISF_LOCAL flag (in IS_ISI) if your program is not a host control
    // system, to make sure your buttons do not conflict with any buttons sent by the host.

    // LFS can display normal buttons in these four screens :

    // - main entry screen
    // - game setup screen
    // - in game
    // - SHIFT+U mode

    // The recommended area for most buttons is defined by :

#define IS_X_MIN 0
#define IS_X_MAX 110

#define IS_Y_MIN 30
#define IS_Y_MAX 170

    // If you draw buttons in this area, the area will be kept clear to
    // avoid overlapping LFS buttons with your InSim program's buttons.
    // Buttons outside that area will not have a space kept clear.
    // You can also make buttons visible in all screens - see below.

    // To delete one button or clear all buttons, send this packet :

    struct IS_BFN // Button FunctioN - delete buttons / receive button requests
    {
        byte Size; // 8
        byte Type; // ISP_BFN
        byte ReqI; // 0
        byte SubT; // subtype, from BFN_ enumeration (see below)

        byte UCID; // connection to send to or from (0 = local / 255 = all)
        byte ClickID; // ID of button to delete (if SubT is BFN_DEL_BTN)
        byte Inst; // used internally by InSim
        byte Sp3;
    };

    enum // the fourth byte of IS_BFN packets is one of these
    {
        BFN_DEL_BTN, //  0 - instruction     : delete one button (must set ClickID)
        BFN_CLEAR, //  1 - instruction		: clear all buttons made by this insim instance
        BFN_USER_CLEAR, //  2 - info            : user cleared this insim instance's buttons
        BFN_REQUEST,
    //  3 - user request    : SHIFT+B or SHIFT+I - request for buttons
    };

    // NOTE : BFN_REQUEST allows the user to bring up buttons with SHIFT+B or SHIFT+I

    // SHIFT+I clears all host buttons if any - or sends a BFN_REQUEST to host instances
    // SHIFT+B is the same but for local buttons and local instances

    // To send a button to LFS, send this variable sized packet

    struct IS_BTN // BuTtoN - button header - followed by 0 to 240 characters
    {
        byte Size; // 12 + TEXT_SIZE (a multiple of 4)
        byte Type; // ISP_BTN
        byte ReqI; // non-zero (returned in IS_BTC and IS_BTT packets)
        byte UCID; // connection to display the button (0 = local / 255 = all)

        byte ClickID; // button ID (0 to 239)
        byte Inst; // some extra flags - see below
        byte BStyle; // button style flags - see below
        byte TypeIn; // max chars to type in - see below

        byte L; // left   : 0 - 200
        byte T; // top    : 0 - 200
        byte W; // width  : 0 - 200
        byte H; // height : 0 - 200

        //	char	Text[TEXT_SIZE]; // 0 to 240 characters of text
    };

    // ClickID byte : this value is returned in IS_BTC and IS_BTT packets.

    // Host buttons and local buttons are stored separately, so there is no chance of a conflict between
    // a host control system and a local system (although the buttons could overlap on screen).

    // Programmers of local InSim programs may wish to consider using a configurable button range and
    // possibly screen position, in case their users will use more than one local InSim program at once.

    // TypeIn byte : if set, the user can click this button to type in text.

    // Lowest 7 bits are the maximum number of characters to type in (0 to 95)
    // Highest bit (128) can be set to initialise dialog with the button's text

    // On clicking the button, a text entry dialog will be opened, allowing the specified number of
    // characters to be typed in.  The caption on the text entry dialog is optionally customisable using
    // Text in the IS_BTN packet.  If the first character of IS_BTN's Text field is zero, LFS will read
    // the caption up to the second zero.  The visible button text then follows that second zero.

    // Text : 0-65-66-0 would display button text "AB" and no caption

    // Text : 0-65-66-67-0-68-69-70-71-0-0-0 would display button text "DEFG" and caption "ABC"

    // Inst byte : mainly used internally by InSim but also provides some extra user flags

#define INST_ALWAYS_ON	128		// if this bit is set the button is visible in all screens
    // NOTE : You should not use INST_ALWAYS_ON for most buttons.  This is a special flag for buttons
    // that really must be on in all screens (including the garage and options screens).  You will
    // probably need to confine these buttons to the top or bottom edge of the screen, to avoid
    // overwriting LFS buttons.  Most buttons should be defined without this flag, and positioned
    // in the recommended area so LFS can keep a space clear in the main screens.

    // BStyle byte : style flags for the button

#define ISB_C1			1		// you can choose a standard
#define ISB_C2			2		// interface colour using
#define ISB_C4			4		// these 3 lowest bits - see below
#define ISB_CLICK		8		// click this button to send IS_BTC
#define ISB_LIGHT		16		// light button
#define ISB_DARK		32		// dark button
#define ISB_LEFT		64		// align text to left
#define ISB_RIGHT		128		// align text to right
    // colour 0 : light grey		(not user editable)
    // colour 1 : title colour		(default:yellow)
    // colour 2 : unselected text	(default:black)
    // colour 3 : selected text		(default:white)
    // colour 4 : ok				(default:green)
    // colour 5 : cancel			(default:red)
    // colour 6 : text string		(default:pale blue)
    // colour 7 : unavailable		(default:grey)

    // NOTE : If width or height are zero, this would normally be an invalid button.  But in that case if
    // there is an existing button with the same ClickID, all the packet contents are ignored except the
    // Text field.  This can be useful for updating the text in a button without knowing its position.
    // For example, you might reply to an IS_BTT using an IS_BTN with zero W and H to update the text.

    // Replies : If the user clicks on a clickable button, this packet will be sent :

    struct IS_BTC // BuTton Click - sent back when user clicks a button
    {
        byte Size; // 8
        byte Type; // ISP_BTC
        byte ReqI; // ReqI as received in the IS_BTN
        byte UCID; // connection that clicked the button (zero if local)

        byte ClickID; // button identifier originally sent in IS_BTN
        byte Inst; // used internally by InSim
        byte CFlags; // button click flags - see below
        byte Sp3;
    };

    // CFlags byte : click flags

#define ISB_LMB			1		// left click
#define ISB_RMB			2		// right click
#define ISB_CTRL		4		// ctrl + click
#define ISB_SHIFT		8		// shift + click
    // If the TypeIn byte is set in IS_BTN the user can type text into the button
    // In that case no IS_BTC is sent - an IS_BTT is sent when the user presses ENTER

    struct IS_BTT // BuTton Type - sent back when user types into a text entry button
    {
        byte Size; // 104
        byte Type; // ISP_BTT
        byte ReqI; // ReqI as received in the IS_BTN
        byte UCID; // connection that typed into the button (zero if local)

        byte ClickID; // button identifier originally sent in IS_BTN
        byte Inst; // used internally by InSim
        byte TypeIn; // from original button specification
        byte Sp3;

        char Text[96]; // typed text, zero to TypeIn specified in IS_BTN
    };

    // OutSim - MOTION SIMULATOR SUPPORT
    // ======

    // The user's car in multiplayer or the viewed car in single player or
    // single player replay can output information to a motion system while
    // viewed from an internal view.

    // This can be controlled by 5 lines in the cfg.txt file :

    // OutSim Mode 0        :0-off 1-driving 2-driving+replay
    // OutSim Delay 1       :minimum delay between packets (100ths of a sec)
    // OutSim IP 0.0.0.0    :IP address to send the UDP packet
    // OutSim Port 0        :IP port
    // OutSim ID 0          :if not zero, adds an identifier to the packet

    // Each update sends the following UDP packet :

    struct OutSimPack
    {
        unsigned Time; // time in milliseconds (to check order)

        Vector AngVel; // 3 floats, angular velocity vector
        float Heading; // anticlockwise from above (Z)
        float Pitch; // anticlockwise from right (X)
        float Roll; // anticlockwise from front (Y)
        Vector Accel; // 3 floats X, Y, Z
        Vector Vel; // 3 floats X, Y, Z
        Vec Pos; // 3 ints   X, Y, Z (1m = 65536)

        int ID; // optional - only if OutSim ID is specified
    };

    // NOTE 1) X and Y axes are on the ground, Z is up.

    // NOTE 2) Motion simulators can be dangerous.  The Live for Speed developers do
    // not support any motion systems in particular and cannot accept responsibility
    // for injuries or deaths connected with the use of such machinery.


    // OutGauge - EXTERNAL DASHBOARD SUPPORT
    // ========

    // The user's car in multiplayer or the viewed car in single player or
    // single player replay can output information to a dashboard system
    // while viewed from an internal view.

    // This can be controlled by 5 lines in the cfg.txt file :

    // OutGauge Mode 0        :0-off 1-driving 2-driving+replay
    // OutGauge Delay 1       :minimum delay between packets (100ths of a sec)
    // OutGauge IP 0.0.0.0    :IP address to send the UDP packet
    // OutGauge Port 0        :IP port
    // OutGauge ID 0          :if not zero, adds an identifier to the packet

    // Each update sends the following UDP packet :

    struct OutGaugePack
    {
        unsigned Time; // time in milliseconds (to check order)

        char Car[4]; // Car name
        word Flags; // OG_FLAGS (see below)
        byte Gear; // Reverse:0, Neutral:1, First:2...
        byte SpareB;
        float Speed; // M/S
        float RPM; // RPM
        float Turbo; // BAR
        float EngTemp; // C
        float Fuel; // 0 to 1
        float OilPress; // BAR
        float Spare1;
        float Spare2;
        float Spare3;
        float Throttle; // 0 to 1
        float Brake; // 0 to 1
        float Clutch; // 0 to 1
        char Display1[16]; // Usually Fuel
        char Display2[16]; // Usually Settings

        int ID; // optional - only if OutGauge ID is specified
    };

#define OG_SHIFTLIGHT	1
#define OG_FULLBEAM		2
#define OG_HANDBRAKE	4
#define OG_PITSPEED		8
#define OG_TC			16
#define OG_HEADLIGHTS	32
#define OG_SIGNAL_L		64
#define OG_SIGNAL_R		128
#define OG_REDLINE		256
#define OG_OILWARN		512
#define OG_1			1024
#define OG_2			2048
#define OG_3			4096
#define OG_4			8192
#define OG_KM			16384
#define OG_BAR			32768
}
//////
#endif // _ISPACKETS_H
